package com.youhome.service.impl;


import com.github.pagehelper.PageInfo;
import com.youhome.mapper.ZipMapper;
import com.youhome.mapper.HotCityMapper;
import com.youhome.model.Point;
import com.youhome.result.AssociateAddress;
import com.youhome.result.AssociateCity;
import com.youhome.result.AssociateZip;
import com.youhome.result.ListHubList;
import com.youhome.service.SolrService;
import com.youhome.utils.SolrUtils;
import com.youhome.utils.StringUtil;
import org.apache.http.client.utils.DateUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.Group;
import org.apache.solr.client.solrj.response.GroupCommand;
import org.apache.solr.client.solrj.response.GroupResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by chen365 on 2018/07/20.
 */
@Service
public class SolrServiceImpl implements SolrService {

    @Value("${solr.host}")
    private String solrHost;

    @Autowired
    private ZipMapper zipMapper;

    @Autowired
    private HotCityMapper hotCityMapper;

    public static void main(String[] args) {
        System.err.println(transformMetachar("now yor"));
    }

    public static String transformMetachar(String input) {
        StringBuffer sb = new StringBuffer();
        try {
            String regex = "[+\\-&|!(){}\\[\\]^\"~*?:(\\)\\s]";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(input);
            while (matcher.find()) {
                matcher.appendReplacement(sb, "\\\\" + matcher.group());
            }
            matcher.appendTail(sb);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    public static String hotCity(String keyword) {
        keyword = keyword.replaceAll(" ", "");
        if (keyword.equalsIgnoreCase("sanfrancisco")) {
            return "San Francisco";
        } else if (keyword.equalsIgnoreCase("losangeles")) {
            return "Los Angeles";
        } else if (keyword.equalsIgnoreCase("newyork")) {
            return "New York";
        } else if (keyword.equalsIgnoreCase("seattle")) {
            return "Seattle";
        } else if (keyword.equalsIgnoreCase("atlanta")) {
            return "Atlanta";
        } else if (keyword.equalsIgnoreCase("boston")) {
            return "Boston";
        } else if (keyword.equalsIgnoreCase("newjersey")) {
            return "New Jersey";
        } else if (keyword.equalsIgnoreCase("houston")) {
            return "Houston";
        } else if (keyword.equalsIgnoreCase("sandiego")) {
            return "San Diego";
        } else if (keyword.equalsIgnoreCase("orlando")) {
            return "Orlando";
        } else {
            return keyword;
        }
    }

    @Override
    public List<AssociateZip> associateSearchByZip(String zip) {
        List<AssociateZip> associateZips = new ArrayList<>();
        long time = System.currentTimeMillis();
        try {
            HttpSolrClient httpSolrClient = new HttpSolrClient.Builder(solrHost)
                    .withConnectionTimeout(10000)
                    .withSocketTimeout(60000)
                    .build();

            final Map<String, String> queryParamMap = new HashMap<>();
            if (!StringUtils.isEmpty(zip)) {
                zip = transformMetachar(zip) + "*";
            }
            queryParamMap.put("q", "zip:" + zip);
            queryParamMap.put("fl", "city,zip");
            queryParamMap.put("group", "true");
            queryParamMap.put("group.field", "zip");
            queryParamMap.put("start", "0");//记录开始位置
            queryParamMap.put("data", "20");//查询的行数

            MapSolrParams mapSolrParams = new MapSolrParams(queryParamMap);
            final QueryResponse response = httpSolrClient.query("listhub", mapSolrParams);
            GroupResponse groupResponse = response.getGroupResponse();
            System.err.println("size:" + groupResponse.getValues().size());
            for (GroupCommand groupCommand : groupResponse.getValues()) {
                List<Group> values = groupCommand.getValues();
                for (Group group : values) {
                    SolrDocumentList result = group.getResult();

                    for (SolrDocument solrDocument : result) {
                        System.err.println("solrDocument" + solrDocument.toString());
                        AssociateZip associateZip = SolrUtils.solrDocumentToPojo(solrDocument, AssociateZip.class);
                        associateZips.add(associateZip);
                    }
                }
            }
            /*
            SolrDocumentList documents = response.getResults();
            System.err.println("数量：" + documents.getNumFound());
            System.err.println("solr-time--1:" + (System.currentTimeMillis() - time));

            for (SolrDocument solrDocument : documents) {
                System.err.println(solrDocument);
                AssociateZip associateZip = SolrUtils.solrDocumentToPojo(solrDocument, AssociateZip.class);
                associateZips.add(associateZip);
            }
            */


        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.err.println("solr-time:" + (System.currentTimeMillis() - time));

        return associateZips;

    }

    @Override
    public List<AssociateCity> associateSearchByCity(String city) {
        List<AssociateCity> associateCities = new ArrayList<>();
        long time = System.currentTimeMillis();
        try {
            HttpSolrClient httpSolrClient = new HttpSolrClient.Builder(solrHost)
                    .withConnectionTimeout(10000)
                    .withSocketTimeout(60000)
                    .build();

            final Map<String, String> queryParamMap = new HashMap<>();
            if (!StringUtils.isEmpty(city)) {
                city = "*" + transformMetachar(city) + "*";
            }
            System.err.println(city);
            queryParamMap.put("q", "city:" + city);
            queryParamMap.put("fl", "city,province");
            queryParamMap.put("group", "true");
            queryParamMap.put("group.field", "city");
            queryParamMap.put("start", "0");//记录开始位置
            queryParamMap.put("data", "20");//查询的行数

            MapSolrParams mapSolrParams = new MapSolrParams(queryParamMap);
            System.err.println(mapSolrParams.toQueryString());

            final QueryResponse response = httpSolrClient.query("listhub", mapSolrParams);

            GroupResponse groupResponse = response.getGroupResponse();
            System.err.println("size:" + groupResponse.getValues().size());
            for (GroupCommand groupCommand : groupResponse.getValues()) {
                List<Group> values = groupCommand.getValues();
                for (Group group : values) {
                    SolrDocumentList result = group.getResult();

                    for (SolrDocument solrDocument : result) {
                        System.err.println("solrDocument" + solrDocument.toString());
                        AssociateCity associateCity = new AssociateCity();//SolrUtils.solrDocumentToPojo(solrDocument, AssociateCity.class);
                        if (solrDocument.get("city") != null) {
                            associateCity.setCity(solrDocument.get("city").toString());
                        }
                        if (solrDocument.get("province") != null) {
                            associateCity.setState(solrDocument.get("province").toString());
                        }
                        associateCities.add(associateCity);
                    }
                }
            }

            /*
            SolrDocumentList documents = response.getResults();
            System.err.println("数量：" + documents.getNumFound());
            System.err.println("solr-time--1:" + (System.currentTimeMillis() - time));

            for (SolrDocument solrDocument : documents) {
                AssociateCity associateZip = SolrUtils.solrDocumentToPojo(solrDocument, AssociateCity.class);
                associateCities.add(associateZip);
            }
            */

        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.err.println("solr-time:" + (System.currentTimeMillis() - time));

        return associateCities;
    }

    @Override
    public List<AssociateAddress> associateSearchByAddress(String address) {
        List<AssociateAddress> associateAddresses = new ArrayList<>();
        long time = System.currentTimeMillis();
        try {
            HttpSolrClient httpSolrClient = new HttpSolrClient.Builder(solrHost)
                    .withConnectionTimeout(10000)
                    .withSocketTimeout(60000)
                    .build();

            final Map<String, String> queryParamMap = new HashMap<>();
            if (!StringUtils.isEmpty(address)) {
                address = "*" + transformMetachar(address) + "*";
            }
            System.err.println(address);
            queryParamMap.put("q", "address:" + address);
            //queryParamMap.put("q", "address:*new\\ yor*");
            queryParamMap.put("fl", "id,address,hero_image,list_price,bedroom_count,bathroom_count,living_area");
            queryParamMap.put("start", "0");//记录开始位置
            queryParamMap.put("data", "20");//查询的行数


            MapSolrParams mapSolrParams = new MapSolrParams(queryParamMap);

            System.err.println(mapSolrParams.toQueryString());

            final QueryResponse response = httpSolrClient.query("listhub", mapSolrParams);

            SolrDocumentList documents = response.getResults();

            System.err.println("数量：" + documents.getNumFound());
            System.err.println("solr-time--1:" + (System.currentTimeMillis() - time));

            for (SolrDocument solrDocument : documents) {
                AssociateAddress associateAddress = new AssociateAddress();// SolrUtils.solrDocumentToPojo(solrDocument, AssociateAddress.class);

                if (solrDocument.get("id") != null) {
                    associateAddress.setHouseId(solrDocument.get("id").toString());
                }
                if (solrDocument.get("address") != null) {
                    associateAddress.setAddress(solrDocument.get("address").toString());
                }
                if (solrDocument.get("hero_image") != null) {
                    associateAddress.setPhoto(solrDocument.get("hero_image").toString());
                }

                if (solrDocument.get("list_price") != null) {
                    associateAddress.setListPrice(Double.valueOf(solrDocument.get("list_price").toString()));
                }

                if (solrDocument.get("bedroom_count") != null) {
                    associateAddress.setBedroomCount(Integer.valueOf(solrDocument.get("bedroom_count").toString()));
                }

                if (solrDocument.get("bathroom_count") != null) {
                    associateAddress.setBathroomCount(Integer.valueOf(solrDocument.get("bathroom_count").toString()));
                }
                if (solrDocument.get("living_area") != null) {
                    associateAddress.setLivingArea(Double.valueOf(solrDocument.get("living_area").toString()));
                }

                associateAddresses.add(associateAddress);
            }

        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.err.println("solr-time:" + (System.currentTimeMillis() - time));

        return associateAddresses;
    }

    @Override
    public PageInfo<ListHubList> searchByBean(String action, String keyword,
                                              Integer pageNumber, Integer pageSize,
                                              String type, Integer beds, Integer baths,
                                              Integer year,
                                              Double minSize, Double maxSize,
                                              Double minPrice, Double maxPrice,

                                              String filed, String direction,

                                              Boolean isStar, Boolean isCheck,
                                              Double minX, Double maxX, Double minY, Double maxY,
                                              Long companyId) {
        if (StringUtils.isEmpty(pageNumber) || pageNumber < 1) {
            pageNumber = 1;
        }
        if (StringUtils.isEmpty(pageSize) || pageSize < 10) {
            pageSize = 10;
        }
        String[] types = new String[]{};
        if (!StringUtils.isEmpty(type)) {
            types = type.split(",");
        }
        long total = 0;

        List<ListHubList> lists = new ArrayList<>();
        long time = System.currentTimeMillis();
        try {
            HttpSolrClient httpSolrClient = new HttpSolrClient.Builder(solrHost)
                    .withConnectionTimeout(10000)
                    .withSocketTimeout(60000)
                    .build();


            final Map<String, String> queryParamMap = new HashMap<>();
            SolrQuery filterQuery = new SolrQuery();

            Integer start = (pageNumber - 1) * pageSize;

            if (!StringUtils.isEmpty(action)) {
                if (action.equals("zip")) {
                    queryParamMap.put("q", "zip:" + keyword);
                }
                if (action.equals("city")) {
                    List<String> items = new ArrayList<>();

                    List<String> zips = new ArrayList<>();
                    keyword = hotCity(keyword);
                    if (keyword.equals("San Francisco") ||
                            keyword.equals("Los Angeles") ||
                            keyword.equals("New York") ||
                            keyword.equals("Seattle") ||
                            keyword.equals("Atlanta") ||
                            keyword.equals("Boston") ||
                            keyword.equals("New Jersey") ||
                            keyword.equals("Houston") ||
                            keyword.equals("San Diago") ||
                            keyword.equals("Orlando")
                            ) {
                        String zipCodes = hotCityMapper.selectZipsByEnName(keyword);
                        zips = Arrays.asList(zipCodes.split(","));
                    } else {
                        zips = zipMapper.selectZipsByCity(keyword);
                    }

                    if (zips != null && zips.size() > 0) {
                        System.err.println(zips.toString());
                        for (String zip : zips) {
                            items.add("zip:" + zip);
                        }
                        System.err.println(String.join(" OR ", items));
                        filterQuery.addFilterQuery(String.join(" OR ", items));
                    } else {
                        queryParamMap.put("q", "city:" + keyword);
                    }
                    queryParamMap.put("q", "*:*");
                }
                if (action.equals("address")) {
                    queryParamMap.put("q", "address:" + keyword);
                }
            } else {
                queryParamMap.put("q", "*:*");
            }


            if (types.length > 0) {
                List<String> property_subtypes = new ArrayList<>();
                for (String str : types) {
                    property_subtypes.add("property_subtype:" + str);
                }
                filterQuery.addFilterQuery(String.join(" OR ", property_subtypes));
            }

            if (!StringUtils.isEmpty(beds) && beds > 0) {
                filterQuery.addFilterQuery("bedroom_count:[ " + beds + " TO *]");
            }
            if (!StringUtils.isEmpty(baths) && baths > 0) {
                filterQuery.addFilterQuery("bathroom_count:[ " + baths + " TO *]");
            }
            if (!StringUtils.isEmpty(year) && year > 0) {
                filterQuery.addFilterQuery("year_built:[ " + year + " TO *]");
            }
            //面积
            if (!StringUtils.isEmpty(minSize) && !StringUtils.isEmpty(maxSize) && minSize > 0 && maxSize > 0) {
                filterQuery.addFilterQuery("living_area:[ " + minSize + " TO " + maxSize + "]");
            } else if (!StringUtils.isEmpty(minSize) && StringUtils.isEmpty(maxSize) && minSize > 0) {
                filterQuery.addFilterQuery("living_area:[ " + minSize + " TO *]");
            } else if (!StringUtils.isEmpty(maxSize) && StringUtils.isEmpty(minSize) && maxSize > 0) {
                filterQuery.addFilterQuery("living_area:[ * TO " + maxSize + "]");
            }
            //价格
            if (!StringUtils.isEmpty(minPrice) && !StringUtils.isEmpty(maxPrice) && minPrice > 0 && maxPrice > 0) {
                filterQuery.addFilterQuery("list_price:[ " + minPrice + " TO " + maxPrice + "]");
            } else if (!StringUtils.isEmpty(minPrice) && StringUtils.isEmpty(maxPrice) && minPrice > 0) {
                filterQuery.addFilterQuery("list_price:[ " + minPrice + " TO *]");
            } else if (!StringUtils.isEmpty(maxPrice) && StringUtils.isEmpty(minPrice) && maxPrice > 0) {
                filterQuery.addFilterQuery("list_price:[ * TO " + maxPrice + "]");
            }

            if (!StringUtils.isEmpty(maxX) && !StringUtils.isEmpty(maxY) && !StringUtils.isEmpty(minX) && !StringUtils.isEmpty(minY)) {
                //经度 longitude(Y) and 纬度latitude (X)
                //左上角坐标
                Point p1 = new Point(minX, maxY);
                //右上角坐标
                Point p2 = new Point(maxX, maxY);
                //右下角坐标
                Point p3 = new Point(maxX, minY);
                //左下角坐标
                Point p4 = new Point(minX, minY);

                List<String> points = new ArrayList<>();

                points.add(minY + " " + maxX);
                points.add(maxY + " " + maxX);
                points.add(maxY + " " + minX);
                points.add(minY + " " + minX);
                points.add(minY + " " + maxX);
                String polygon = String.join(",", points);
                System.err.println(polygon);
                filterQuery.addFilterQuery("{!field f=point}Intersects(POLYGON((" + polygon + ")))"); //距离过滤函数
            }

            if (!StringUtils.isEmpty(isStar)) {
                filterQuery.addFilterQuery("is_star:" + isStar);
            }

            if (!StringUtils.isEmpty(isCheck)) {
                filterQuery.addFilterQuery("is_check:" + isCheck);
            }

            //排序
            if (!StringUtils.isEmpty(filed) && !StringUtils.isEmpty(direction)) {
                queryParamMap.put("sort", StringUtil.transitionOrderBy(filed) + " " + direction);
            } else {
                filterQuery.setSort("year_built", SolrQuery.ORDER.desc);
            }


            filterQuery.addFilterQuery("enabled:true");
            filterQuery.addFilterQuery("listing_status:Active");

            queryParamMap.put("fl", "id,address,list_price,listing_category,listing_key,listing_status,listing_date,provider_name,provider_url,provider_category,bedroom_count,bathroom_count,property_type,property_subtype,hero_image,living_area,lot_size,year_built,is_star,is_check,latitude,longitude");

            queryParamMap.put("start", String.valueOf(start));//记录开始位置

            queryParamMap.put("data", String.valueOf(pageSize));//查询的行数

            MapSolrParams mapSolrParams = new MapSolrParams(queryParamMap);

            ModifiableSolrParams modifiableSolrParams = new ModifiableSolrParams();

            modifiableSolrParams.add(mapSolrParams);
            modifiableSolrParams.add(filterQuery);

            System.err.println(modifiableSolrParams.toQueryString());

            final QueryResponse response = httpSolrClient.query("listhub", modifiableSolrParams);


            SolrDocumentList documents = response.getResults();
            total = documents.getNumFound();
            System.err.println("数量：" + documents.getNumFound());
            //System.err.println("solr-time--1:" + (System.currentTimeMillis() - time));

            for (SolrDocument solrDocument : documents) {
                //System.err.println(solrDocument);
                //HouseListResult listHubList = SolrUtils.solrDocumentToPojo(solrDocument, HouseListResult.class);
                ListHubList listHubList = new ListHubList();
                if (solrDocument.get("id") != null) {
                    listHubList.setHouseId(String.valueOf(solrDocument.get("id")));
                }
                if (solrDocument.get("address") != null) {
                    listHubList.setAddress(String.valueOf(solrDocument.get("address")));
                }
                if (solrDocument.get("list_price") != null) {
                    listHubList.setListPrice(Double.valueOf(solrDocument.get("list_price").toString()));
                }
                if (solrDocument.get("listing_category") != null) {
                    listHubList.setListingCategory(String.valueOf(solrDocument.get("listing_category")));
                }
                if (solrDocument.get("listing_key") != null) {
                    listHubList.setListingKey(String.valueOf(solrDocument.get("listing_key")));
                }
                if (solrDocument.get("listing_status") != null) {
                    listHubList.setListingStatus(String.valueOf(solrDocument.get("listing_status")));
                }
                if (solrDocument.get("listing_date") != null) {
                    //System.err.println("listing_date:"+solrDocument.get("listing_date").toString());
                    listHubList.setListingDate(DateUtils.parseDate(solrDocument.get("listing_date").toString(), new String[]{"yyyy-MM-dd"}));
                }
                if (solrDocument.get("provider_name") != null) {
                    listHubList.setProviderName(String.valueOf(solrDocument.get("provider_name")));
                }
                if (solrDocument.get("provider_url") != null) {
                    listHubList.setProviderUrl(String.valueOf(solrDocument.get("provider_url")));
                }
                if (solrDocument.get("provider_category") != null) {
                    listHubList.setProviderCategory(String.valueOf(solrDocument.get("provider_category")));
                }
                if (solrDocument.get("bedroom_count") != null) {
                    listHubList.setBedroomCount(Integer.valueOf(solrDocument.get("bedroom_count").toString()));
                }
                if (solrDocument.get("bathroom_count") != null) {
                    listHubList.setBathroomCount(Integer.valueOf(solrDocument.get("bathroom_count").toString()));
                }
                if (solrDocument.get("property_type") != null) {
                    listHubList.setPropertyType(String.valueOf(solrDocument.get("property_type").toString()));
                }
                if (solrDocument.get("property_subtype") != null) {
                    listHubList.setPropertySubtype(String.valueOf(solrDocument.get("property_subtype").toString()));
                }
                if (solrDocument.get("hero_image") != null) {
                    listHubList.setHeroImage(String.valueOf(solrDocument.get("hero_image").toString()));
                }
                if (solrDocument.get("living_area") != null) {
                    listHubList.setLivingArea(Double.valueOf(solrDocument.get("living_area").toString()));
                }
                if (solrDocument.get("lot_size") != null) {
                    listHubList.setLotSize(Double.valueOf(solrDocument.get("lot_size").toString()));
                }
                if (solrDocument.get("year_built") != null) {
                    listHubList.setYearBuilt(Integer.valueOf(solrDocument.get("year_built").toString()));
                }
                if (solrDocument.get("is_star") != null) {
                    listHubList.setIsStar(Boolean.valueOf(solrDocument.get("is_star").toString()));
                }
                if (solrDocument.get("latitude") != null) {
                    listHubList.setLatitude(Double.valueOf(solrDocument.get("latitude").toString()));
                }
                if (solrDocument.get("longitude") != null) {
                    listHubList.setLongitude(Double.valueOf(solrDocument.get("longitude").toString()));
                }
                if (solrDocument.get("is_check") != null) {
                    listHubList.setIsCheck(Boolean.valueOf(solrDocument.get("is_check").toString()));
                }

                lists.add(listHubList);
            }

        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.err.println("solr-time:" + (System.currentTimeMillis() - time));

        PageInfo pageInfo = new PageInfo();
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(total);

        int pages = (int) ((total + pageSize - 1) / pageSize);// (int) Math.ceil((total / pageSize));
        pageInfo.setPages(pages);
        pageInfo.setPageNum(pageNumber);

        pageInfo.setList(lists);

        return pageInfo;
    }
}
